package cn.wuxing.mediation.web.controller.util;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.wuxing.mediation.system.domain.MessageNotifications;
import com.alibaba.xxpt.gateway.shared.api.request.OapiMoziEmployeeListEmployeesByCodesRequest;
import com.alibaba.xxpt.gateway.shared.api.request.OapiMoziFusionPageSearchEmployeeRequest;
import com.alibaba.xxpt.gateway.shared.api.request.OapiMoziOrganizationListOrganizationsByCodesRequest;
import com.alibaba.xxpt.gateway.shared.api.request.OapiMoziOrganizationPageSubOrganizationCodesRequest;
import com.alibaba.xxpt.gateway.shared.api.response.OapiMoziEmployeeListEmployeesByCodesResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiMoziFusionPageSearchEmployeeResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiMoziOrganizationListOrganizationsByCodesResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiMoziOrganizationPageSubOrganizationCodesResponse;
import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.alibaba.xxpt.gateway.shared.client.http.PostClient;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;

@Slf4j
@Service
public class OrganizationEmployeeFetcher {

    private static final String SUB_ORG_CODES_URL = "/mozi/organization/pageSubOrganizationCodes";
    public static final String ORG_DETAILS_URL = "/mozi/organization/listOrganizationsByCodes";
    private static final String EMPLOYEE_CODES_URL = "/mozi/organization/pageOrganizationEmployeeCodes";
    private static final String EMPLOYEE_DETAILS_URL = "/mozi/employee/listEmployeesByCodes";
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final String SEND_MESSAGE_URL = "/message/workNotification";

    @Value("${dingIf.APP_KEY}")
    private String appKey;

    @Value("${dingIf.APP_SECRET}")
    private String appSecret;

    @Value("${dingIf.TENANT_ID}")
    private String tenantId;

    @Value("${dingIf.DOMAIN_NAME}")
    private String domainName;

    @Value("${dingQr.PROTOCAL}")
    private String protocol;

    @Resource
    private DataProcessor dataProcessor;

    private volatile ExecutableClient executableClient;

    private synchronized ExecutableClient getExecutableClient() {
        if (executableClient == null) {
            executableClient = ExecutableClient.getInstance();
            executableClient.setAccessKey(appKey);
            executableClient.setSecretKey(appSecret);
            executableClient.setDomainName(domainName);
            executableClient.setProtocal(protocol);
            executableClient.setTimeout(300_000);
            executableClient.init();
        }
        return executableClient;
    }

    /**
     * 浙政钉发送消息
     *
     * @param messageNotifications
     * @return
     */
    public String sendMessage(MessageNotifications messageNotifications) {
        ExecutableClient executableClient = getExecutableClient();

        PostClient postClient = executableClient.newPostClient(SEND_MESSAGE_URL);

//        postClient.addParameter("organizationCodes",organizationCode);//接收者的部门id列表
        postClient.addParameter("receiverIds", messageNotifications.getAccountId());//多人,分割
        postClient.addParameter("tenantId", tenantId);
        postClient.addParameter("bizMsgId", String.valueOf(messageNotifications.getId()));

        String template = "你有一条待处理纠纷事项，编号为【" + messageNotifications.getEventCode() + "】，请及时处理。";
        postClient.addParameter("msg", "{\"msgtype\":\"text\",\"text\":{\"content\":\"" + template + "\"}}");

        String apiResult = postClient.post();
        log.info("=======================返回成功:{}", apiResult);
        JSONObject entries = JSONUtil.parseObj(apiResult);
        if (entries.containsKey("success")) {
            return entries.getJSONObject("content").getStr("msgId");
        }
        return null;
    }

    public void initOrganizationalStructure(String organizationCode) {
        List<String> allOrgCodes = getAllOrganizationCodes(organizationCode);

        getAllEmployees(allOrgCodes);
//        log.info("=================allOrgs:{}", JSONUtil.toJsonStr(allOrgs));
//        log.info("=================allEmployees:{}", JSONUtil.toJsonStr(allEmployees));
    }

    public List<String> getAllOrganizationCodes(String parentCode) {
        Queue<String> queue = new LinkedList<>();
        List<String> orgCodes = new ArrayList<>();
        List<String> allOrgCodes = new ArrayList<>();
        queue.offer(parentCode);
//        orgCodes.add(parentCode);
        allOrgCodes.add(parentCode);
        while (!queue.isEmpty()) {
            String currentCode = queue.poll();
            int pageNo = 1;
            boolean hasMore;
            do {
                ExecutableClient client = getExecutableClient();
                OapiMoziOrganizationPageSubOrganizationCodesRequest request = new OapiMoziOrganizationPageSubOrganizationCodesRequest();
                request.setOrganizationCode(currentCode);
                request.setPageNo(pageNo);
                request.setPageSize(100);
                request.setTenantId(Long.valueOf(tenantId));
                OapiMoziOrganizationPageSubOrganizationCodesResponse response =
                        client.newIntelligentGetClient(SUB_ORG_CODES_URL).get(request);

                List<String> subOrgCodes = parseList(response.getContent().getData(), String.class);
                queue.addAll(subOrgCodes);
                orgCodes.addAll(subOrgCodes);
                allOrgCodes.addAll(subOrgCodes);
                hasMore = subOrgCodes.size() == 100;
                pageNo++;
            } while (hasMore);
            dataProcessor.addOrganizations(getOrganizationDetails(orgCodes));
            orgCodes = new ArrayList<>();
        }
        return allOrgCodes;
    }

    public List<Organization> getOrganizationDetails(List<String> orgCodes) {
        if (orgCodes.isEmpty()) return Collections.emptyList();
        List<Organization> organizations = new ArrayList<>();
        int batchSize = 100;
        for (int i = 0; i < orgCodes.size(); i += batchSize) {
            List<String> batch = orgCodes.subList(i, Math.min(i + batchSize, orgCodes.size()));
            try {
                ExecutableClient client = getExecutableClient();
                OapiMoziOrganizationListOrganizationsByCodesRequest request = new OapiMoziOrganizationListOrganizationsByCodesRequest();
                request.setOrganizationCodes(batch);
                request.setTenantId(Long.valueOf(tenantId));
                OapiMoziOrganizationListOrganizationsByCodesResponse response =
                        client.newIntelligentPostClient(ORG_DETAILS_URL).post(request);
                organizations.addAll(parseList(response.getContent().getData(), Organization.class));
            } catch (Exception e) {
                log.error("Error fetching organization details for batch {}: ", batch, e);
            }
        }
        return organizations;
    }

    public void getAllEmployees(List<String> orgCodes) {
        List<Employee> employees = new ArrayList<>();
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Future<List<Employee>>> futures = new ArrayList<>();

        for (String orgCode : orgCodes) {
            futures.add(executorService.submit(() -> getEmployeesFromOrg(orgCode)));
        }

        for (Future<List<Employee>> future : futures) {
            try {
                dataProcessor.addEmployees(future.get());
            } catch (Exception e) {
                log.error("Error fetching employees: ", e);
            }
        }

        executorService.shutdown();
    }

    private List<Employee> getEmployeesFromOrg(String orgCode) {
        List<Employee> employees = new ArrayList<>();
        int pageNo = 1;
        boolean hasMore;

        do {
            ExecutableClient client = getExecutableClient();
            OapiMoziOrganizationPageSubOrganizationCodesRequest request = new OapiMoziOrganizationPageSubOrganizationCodesRequest();
            request.setOrganizationCode(orgCode);
            request.setPageNo(pageNo);
            request.setPageSize(100);
            request.setTenantId(Long.valueOf(tenantId));

            OapiMoziOrganizationPageSubOrganizationCodesResponse response =
                    client.newIntelligentGetClient(EMPLOYEE_CODES_URL).get(request);
            List<String> employeeCodes = parseList(response.getContent().getData(), String.class);
            employees.addAll(getEmployeeDetails(employeeCodes));
            hasMore = employeeCodes.size() == 100;
            pageNo++;
        } while (hasMore);

        return employees;
    }

    private List<Employee> getEmployeeDetails(List<String> employeeCodes) {
        if (employeeCodes.isEmpty()) return Collections.emptyList();
        List<Employee> employees = new ArrayList<>();
        try {
            ExecutableClient client = getExecutableClient();
            OapiMoziEmployeeListEmployeesByCodesRequest request = new OapiMoziEmployeeListEmployeesByCodesRequest();
            request.setEmployeeCodes(employeeCodes);
            request.setTenantId(Long.valueOf(tenantId));
            OapiMoziEmployeeListEmployeesByCodesResponse response =
                    client.newIntelligentPostClient(EMPLOYEE_DETAILS_URL).post(request);
            if(response.getContent()!=null) {
                employees.addAll(parseList(response.getContent().getData(), Employee.class));
            }else{
                log.error("Error fetching employee details for codes {}: ,Response Data is:{}", employeeCodes,JSONUtil.toJsonStr(response));
            }
        } catch (Exception e) {
            log.error("Error fetching employee details for codes {}: ", employeeCodes, e);
        }
        return employees;
    }

    private <T> List<T> parseList(String data, Class<T> clazz) {
        try {
            return JSONUtil.toList(data,clazz);
        } catch (Exception e) {
            log.error("Error parsing response: ", e);
            return Collections.emptyList();
        }
    }
}
